﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BfLib.Text
{
    public class WordCycler
    {
        //private const string _sletters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private const string _slower =   "abcdefghijklmnopqrstuvwxyz";
        private const string _supper =   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private const string _sspecial = " ,.<>\\|\"';:{}[]!@#$%^&*() \t\n-=_+`~";
        private const string _snumbers = "0123456789";

        private string _charSetStr = string.Empty;
        private int[] _charSetInts;
        private char[] _charSet;
        private char[] _tryChars;
        private int _charToInc = 0;
        private int[] _charInts;

        public WordCycler(bool lower, bool upper, bool special, bool numbers, int shortest, int longest)
        {
            StringBuilder sb = new StringBuilder();

            if (lower)
            {
                sb.Append(_slower);
            }
            if (upper)
            {
                sb.Append(_supper);
            }
            if (numbers)
            {
                sb.Append(_snumbers);
            }
            if (special)
            {
                sb.Append(_sspecial);
            }

            _charSetStr = sb.ToString();

            if (_charSetStr.Length == 0)
            {
                throw new ArgumentException("Must select at least one character set");
            }


            _charSet = new char[_charSetStr.Length];
            for (int i = 0; i < _charSet.Length; i++)
            {
                _charSet[i] = _charSetStr[i];
            }

            _charSetInts = new int[_charSetStr.Length];
            for (int i = 0; i < _charSetInts.Length; i++)
            {
                _charSetInts[i] = Convert.ToInt32(_charSetStr[i]);
            }
            

            _tryChars = new char[shortest];// = new string(_referenceString[0], shortest);
            _charToInc = _tryChars.Length - 1;
            _charInts = new int[shortest];
            int charSetCursor = 0;


            int curIndex = _charInts.Length-1;
            bool finished=false;

            sb = new StringBuilder();

            using (System.IO.StreamWriter file = new System.IO.StreamWriter("out.txt"))
            {
                for (int i = 0; i < 500; i++)
                {
                    sb.Clear();
                    IncrementPassword(ref curIndex, ref finished, ref charSetCursor);

                    foreach (int n in this._charInts)
                    {
                        sb.Append(String.Format("{0},", StringLib.PadInt(n, 2)));
                    }
                    file.WriteLine(sb.ToString());
                }
            }


            

        }

        private void IncrementPassword(ref int CurrentIncIndex, ref bool Finished, ref int CharSetCursor)
        {
            _charInts[CurrentIncIndex] = _charSetInts[CharSetCursor];

            if (CharSetCursor == _charSetInts.Length - 1)
            {
                for (int i = CurrentIncIndex; i < _charInts.Length; i++)
                {
                    _charInts[i] = _charSetInts[0];
                }
                //Finished = CurrentIncIndex == 0;
                CurrentIncIndex--;
                CharSetCursor = 0;
            }
            else
            {
                CharSetCursor++;
            }

            if (CharSetCursor == _charSetInts[_charSetInts.Length - 1])
            {
                //if we are at the end of possibles to the CurrentIncIndex char,
                //increment the next down char and set ann subsequent chars to _charSetInts[0]
                _charInts[CurrentIncIndex - 1] += 1;
                for (int i = CurrentIncIndex; i < _charInts.Length - 1; i++)
                {
                    _charInts[i] = _charSetInts[0];
                }

                if (CurrentIncIndex == 0)
                {
                    Finished = true;
                }
                else
                {
                    CurrentIncIndex--;
                }

                CharSetCursor = 0;
            }
            else
            {
                _charInts[CurrentIncIndex]++;
            }
            
            /*
             aaa
             aab
             aac
             aba
             abb
             abc
             aca
             acb
             acc
             caa
             cab
             cac
             cba
             cbb
             cbc
             cca
             ccb
             ccc
             */ 
        }
    }
}
